package baduga.server;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


public class Serwer {
	
	
	/** Kolekcja graczy */
	private HashMap<String, Player> colPlayers = new HashMap<String, Player>();
	
	/** Kolekcja stołów */
	private HashMap<String, Table> colTables = new HashMap<String, Table>();
	
	
	/**
	 * Zawiera informacje ile mamy graczy lub stołów
	 * 0 - Gracze
	 * 1 - Stoły
	 * 
	 * */

	/**
	 * 
	 * Przechowuje karty gracza
	 * 
	 */
	private Cards cardDB[] = new Cards[52];
	

	
	/**
	 * Konstruktor inicjujący
	 * 
	 * 
	 */
	public Serwer()
	{
		generateCards();
	}
	
	
	
	
	/**
	 * Generuje globalną talie kart
	 * 
	 */
	private final void generateCards()
	{
		//Def
		int colorsLimit,
			figureLimit,
			index;
		
		//Init.
		colorsLimit = 4;
		figureLimit = 13;
		index = 0;
		
		for(int i = 0; i < colorsLimit; i++)
		{
			
			for(int j = 0; j < figureLimit; j++)
			{
				cardDB[index] = new Cards(j, i);
				
				++index;
			}
		}
		
		
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	/**
	 * Dodaje gracza do listy
	 * 
	 * @param colPlayers
	 * @param key
	 * @return
	 */
	public Object[] addPlayer(final Player colPlayers)
	{
		//Inicjalizacja
		Object[] data;
		
		//Definicja
		data = new Object[] {false, null};
		
		if(checkPlayerName(colPlayers.getNickName()))
		{
			//Operacja Atomooowa!!!!
			synchronized(this)
			{
				if(checkPlayerName(colPlayers.getNickName()))
				{
					//Przechowuje UUID
					String tmpKey;
					
					//Licznik prób
					int attemptCount = -1;
					
					
					
					
					do
					{
						tmpKey = UUID.randomUUID().toString();
						++attemptCount;
						
					}
					while(this.colPlayers.containsKey(tmpKey) && Game_Cfg.UUID_ATMP_LIM > attemptCount);
					
					if(Game_Cfg.UUID_ATMP_LIM > attemptCount )
					{
						this.colPlayers.put(tmpKey, colPlayers);
						
						//Ustaweenie ID
						colPlayers.setPlayerId(tmpKey);
						
						data[0] = true;
						data[1] = tmpKey;
					}
					else
					{
						data[1] = 0x00FE;
					}
				}
				else
				{
					data[1] = 0x03FF;
				}
	
			}
		}
		else
		{
			data[1] = 0x03FF;
		}
		
		return data;
	}
	
	

	
	
	/**
	 * Usuwa Gracza z Listy
	 * 
	 * @param key
	 * @return
	 */
	public Object[] removePlayer(String key)
	{
		
		//Inicjalizacja
		Object[] rData;
		
		//Definicja
		rData = new Object[] {false, null};
		
		//
		
		if(this.colPlayers.containsKey(key))
		{
			this.colPlayers.remove(key);
			
			rData[0] = true;
		}
		else
		{
			rData[1] = 0x03FF;
		}
		
		
		return rData;
	}
	
	
	/**
	 * Dodaje stół w wyniku działania zwraca informację o powodzeniu + Identyfikator
	 * 
	 * @param colTable
	 * @param key
	 * @return
	 */
	public Object[] addTable(Table colTable)
	{
		//Inicjalizacja
		Object[] data;
		
		//Definicja
		data = new Object[] {false, null};
		
		
		if(checkTableName(colTable.getName()))
		{
			//Operacja Atomooowa!!!!
			synchronized(this)
			{
				if(checkTableName(colTable.getName()))
				{
					//Przechowuje UUID
					String tmpKey;
					
					//Licznik prób
					int attemptCount = 0;
					
					
					
					
					do
					{
						tmpKey = UUID.randomUUID().toString();
						++attemptCount;
						
					}
					while(this.colTables.containsKey(tmpKey) && Game_Cfg.UUID_ATMP_LIM > attemptCount);
					
					if(Game_Cfg.UUID_ATMP_LIM > attemptCount)
					{
						this.colTables.put(tmpKey, colTable);
						
						//Ustaweenie ID
						colTable.setTableId(tmpKey);
						
						data[0] = true;
						data[1] = tmpKey;
					}
					else
					{
						data[1] = 0x00FE;
					}
				}
				else
				{
					data[1] = 0x03DF;
				}
	
			} //Synhro Block
		}
		else
		{
			data[1] = 0x03DF;
		}
		
		return data;
	}
	
	/**
	 * Usuwa stół
	 * 
	 * @param key
	 * @return
	 */
	public Object[] removeTable(String key)
	{
		
		//Inicjalizacja
		Object[] rData;
		
		//Definicja
		rData = new Object[] {false, null};
		
		//
		
		if(this.colTables.containsKey(key))
		{
			this.colTables.remove(key);
			
			rData[0] = true;
		}
		else
		{
			rData[1] = 0x03FF;
		}
		
		
		return rData;
	}
	
	
	
	@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
	/**
	 * 
	 * Funkcja Sprawdza czy nickname gracza nie jest w użyciu
	 * 
	 * @param nickname
	 * @return
	 */
	public boolean checkPlayerName(String nickname)
	{
		
		//TODO: Thread not safe
	
		boolean opStatus = true;
		
		if(!colPlayers.isEmpty())
		{	
			//Operacja Atomooowa!!!!
			synchronized(this)
			{
				final Map<String, Player> tmpMap = colPlayers;
	
				
				for(final Player entry : tmpMap.values())
				{
					
					if(entry.getNickName() == nickname)
					{
						opStatus = false;
						break;
					}
					
				}
			}
			
			
		}

		
		return opStatus;
		
	}
	
	
	
	@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
	/**
	 * 
	 * Funkcja Sprawdza czy nazwa stołu nie jest używana
	 * 
	 * @param nickname
	 * @return
	 */
	public boolean checkTableName(String nickname)
	{
		
		//TODO: Thread not safe
	
		boolean opStatus = true;
		
		if(!colTables.isEmpty())
		{		
			//Operacja Atomooowa!!!!
			synchronized(this)
			{
				final Map<String, Table> tmpMap = colTables;
	
				
				for(final Table entry : tmpMap.values())
				{
					
					if(entry.getName() == nickname)
					{
						opStatus = false;
						break;
					}
					
				}
			}
			
			
		}

		return opStatus;
		
	}
	

	
	//===
	
	
	@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
	/**
	 * Funkcja pobiera status gracza (Aby nie robić przeszukiwania)
	 * 
	 * @param playerID
	 * @return
	 */
	public int getPlayerStatus(String playerID)
	{
		int rStatus = -1;
		
		if(colPlayers.containsKey(playerID))
		{
			Player tmp = colPlayers.get(playerID);
			
			rStatus = tmp.getStatusPlayer();
		}
		
		return rStatus;

	}
	
	
	/**
	 * Funkcja zwraca gracza o podanym UUID
	 * 
	 * @param idPlayer
	 * @return
	 */
	public Object[] getPlayer(String idPlayer)
	{
		//Definicja
		Object[] rData;
		
		//Inicjalizacja
		rData = new Object[] {
				false,
				null
		};

		
		//Spr czy istnieje gracz
		if(colPlayers.containsKey(idPlayer))
		{
			rData[0] = true;
			rData[1] = colPlayers.get(idPlayer);
		}
		else
		{
			rData[1] = 0x03FE;
		}
		
		return rData;
	}
	
	
	/**
	 * Funkcja zwaraca stół o poddany UUID
	 * 
	 * @param idTable
	 * @return
	 */
	public Object[] getTable(String idTable)
	{
		//Definicja
		Object[] rData;
		
		//Inicjalizacja
		rData = new Object[] {
				false,
				null
		};
		
		
		//Spr czy istnieje gracz
		if(colTables.containsKey(idTable))
		{
			rData[0] = true;
			rData[1] = colTables.get(idTable);
		}
		else
		{
			rData[1] = 0x03DE;
		}
		
		return rData;
	}
	
	
	/**
	 * Pobiera Listę stołów
	 * 
	 * - nData
	 * [0] - recordLimit
	 * [1] - row
	 * 
	 * @return
	 */
	public Object[][] getTableList(int[] nData)
	{
		//Def.
		Object resData[][];
		int lSize, tSize, j, k;
		
		//Init.
		lSize = nData[0] * (nData[1] - 1);
		j = 1;
		k = -1;
		
		resData = new Object[][] {
			new Object[] {
				false,
				null
			},
			null
		};
		
		
		
		
		
		
		if(colTables.size() >= lSize)
		{
			
			
			resData[1] = new Object[ (colTables.size() - lSize ) * 6 ];
			
			//Ustawienie Flagi
			resData[0][0] = true; 
			
			//Skiper
	
			final Map<String, Table> tmpMap = colTables;
			
	
			//Pomija lSize rekordów, a potem zczytuje, aż do k < nData[0]
			for(final Table entry : tmpMap.values())
			{

				
				
				
				/**
				 *  0 - "Nazwa stołu", 
				 *  1 - "Min. Kwota", 
				 *  2 - "Ile graczy/obserwatorów", 
				 *  3 - "Status", 
				 *  4 - "Działania"
				 *  5 - ID
				 * 
				 * 
				 */
				if(j >= lSize)
				{
					
					//TODO: WatchOut serialization of class
					resData[1][++k]   = entry.getName();
					resData[1][++k] = entry.getMinCash();
					resData[1][++k] = entry.getCountOfPlayersAndObservers();
					resData[1][++k] = entry.getStatus();
					resData[1][++k] = "";
					resData[1][++k] = entry.getTableId();

				}
				
	
				++j;
			}
			
			
		}
		else
		{
			resData[0][1] = 0x03DD;
		}
			
		
		
		
		return resData;
	}
		
	
	/**
	 * Funkcja przenosi indeksowanie z [0, n-1] ma [1, n]
	 * 
	 * @param index
	 * @return
	 */
	public Cards getCard(int index)
	{
		//Ochrona indeksu
		if(index > 0 && index < cardDB.length + 1)
			return cardDB[index - 1];
		else
			return null;
	}
	
	
	/**
	 * Pobiera ilość kart zawartych w talii
	 * 
	 * @return
	 */
	public int getCountOfCards()
	{
		return cardDB.length;
	}
	
	//==

}
